Retirado do artigo Miller et al. (2019). Distance sampling in R. Journal of Statistical Sofware 89(1)

# instalar pacotes necessários
#install.packages("Distance")

# instalar pacotes adicionais
#install.packages("mrds")
#install.packages("dsm")
#install.packages("mads")
#install.packages("dsims")

# carregar pacotes 
library(Distance)
Carregando pacotes exigidos: mrds
This is mrds 2.2.8
Built: R 4.3.0; ; 2023-04-28 17:39:52 UTC; unix

Attaching package: ‘Distance’

The following object is masked from ‘package:mrds’:

    create.bins
library(dplyr)
library(DT)
library(flextable)

Attaching package: ‘flextable’

The following object is masked from ‘package:purrr’:

    compose

The following objects are masked from ‘package:plotly’:

    highlight, style

The following objects are masked from ‘package:ggpubr’:

    border, font, rotate
library(ggplot2)
library(lubridate)
library(plotly)
library(readr)
library(readxl)
library(stringr)
library(tibble)
library(tidyr)

# carregar as funções da pasta R
# carregar função script_carregar_funções_pasta_r.R
source(
  paste0(
    here::here(),
    "/R/minhas_funcoes.R"
  )
)

# carregar dados
cutia_tap_arap <- transformar_para_distanceR_covariaveis() |> 
  filter(
    uc_name == "Resex Tapajos-Arapiuns",
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)
  
# readr::write_excel_csv(
#   cutia_tap_arap,
#   paste0(
#     here::here(),
#     "/data/cutia_tap_arap.csv"
#   ), 
# )

cutia_tap_arap |> 
  DT::datatable(filter = "top")
cutia_tap_arap |> 
  count(Region.Label)

cutia_tap_arap |> 
  count(Sample.Label)

Formatação do conjunto de dados

Variáveis necessárias para o data.frame:

Transectos que foram amostrados, mas que não tiveram observações (n = 0) devem ser incluídos no conjunto de dados com NA nas observações de distância e qualquer outra covariael para a qual não se tenha observação.

# cutia_tap_arap |> 
#   complete(Region.Label, Sample.Label, sp_name) |> 
#   datatable(filter = list(position = "top"))

Jogar a imputacao de NAs pra dentro da funcao carregar dados completos.

Determinando a distância para truncar os dados

# desenha o grafico com a distribuicao de distancias perpendiculares
cutia_tap_arap |> 
  plotar_distribuicao_distancia_interativo()
Warning: Continuous y aesthetic
ℹ did you forget `aes(group = ...)`?

Ajustando funções de detecção no R

Cutias da Resex Tapajós-Arapiuns

Half-Normal sem termos de ajuste

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, sem termo de ajuste.

# ajustando a função de detecção para uma distancia de truncamento de 20 metros
# Key function - Half-normal 
cutia_tap_arap_hn <- cutia_tap_arap |> 
  ds(
    truncation = 20,
    key = "hn",
    adjustment = NULL
  )
Fitting half-normal key function
AIC= 7227.642
Warning: Some observations not included in the analysis

Half-Normal com termos de ajuste Hermite-Polynomial

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, com termo de ajuste do tipo Hermite-polynomial.

# ajustando a função de detecção para uma distancia de truncamento de 20 metros
# Key function - Half-normal 
cutia_tap_arap_hn_herm <- cutia_tap_arap |> 
  ds(
    truncation = 20,
    key = "hn",
    adjustment = "herm"
  )
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 7227.642
Fitting half-normal key function with Hermite(4) adjustments
AIC= 7229.142

Half-normal key function selected.
Warning: Some observations not included in the analysis

Half-Normal com termos de ajuste Cosine

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, com termo de ajuste do tipo Cosine.

# ajustando a função de detecção para uma distancia de truncamento de 20 metros
# Key function - Half-normal 
cutia_tap_arap_hn_cos <- cutia_tap_arap |> 
  ds(
    truncation = 20,
    key = "hn"
    )
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 7227.642
Fitting half-normal key function with cosine(2) adjustments
AIC= 7207.469
Fitting half-normal key function with cosine(2,3) adjustments
AIC= 7201.248
Fitting half-normal key function with cosine(2,3,4) adjustments
Warning: Detection function is not strictly monotonic!AIC= 7152.177
Fitting half-normal key function with cosine(2,3,4,5) adjustments
Warning: Detection function is not strictly monotonic!AIC= 7146.681
Fitting half-normal key function with cosine(2,3,4,5,6) adjustments
Warning: Detection function is not strictly monotonic!AIC= 7129.427
Warning: Detection function is not strictly monotonic!Warning: Some observations not included in the analysis

Hazard-Rate sem termos de ajuste

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key.

# Key function - Hazard-rate 
cutia_tap_arap_hr <- cutia_tap_arap |> 
  ds(
    truncation = 20,
     key = "hr",
    adjustment = NULL
  )
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 6907.541
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Some observations not included in the analysis

Hazard-Rate com termos de ajuste Simple-polynomial

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key e termo de ajuste do tipo polinomial simples.

# Key function - Hazard-rate 
cutia_tap_arap_hr_poly <- cutia_tap_arap |> 
  ds(
    truncation = 20,
     key = "hr",
    adjustment = "poly"
  )
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 6907.541
Fitting hazard-rate key function with simple polynomial(4) adjustments
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Model fitting did not converge. Try different initial values or different model
  Model failed to converge.

Hazard-rate key function selected.
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Some observations not included in the analysis

Hazard-Rate com termos de ajuste Cosine

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key e termo de ajuste do tipo cosseno.

# Key function - Hazard-rate 
cutia_tap_arap_hr_cos <- cutia_tap_arap |> 
  ds(
    truncation = 20,
    key = "hr"
    )
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 6907.541
Fitting hazard-rate key function with cosine(2) adjustments
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Model fitting did not converge. Try different initial values or different model
  Model failed to converge.

Hazard-rate key function selected.
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Some observations not included in the analysis
plot(cutia_tap_arap_hn, breaks = seq(0, 20, 2.5))

plot(cutia_tap_arap_hn_herm, breaks = seq(0, 20, 2.5))

plot(cutia_tap_arap_hn_cos, breaks = seq(0, 20, 2.5))

plot(cutia_tap_arap_hr, breaks = seq(0, 20, 2.5))

plot(cutia_tap_arap_hr_poly, breaks = seq(0, 20, 2.5))

plot(cutia_tap_arap_hr_cos, breaks = seq(0, 20, 2.5))

Ajustando um modelo ao dados das cutias, configurando uma distância limite de 20m e usando Uniform como key function a séria de ajuste com o argumento adjustment ee especificando a ordem com o argumento order.

cutia_unifcos <- cutia_tap_arap |> 
  ds(truncation = 20,
     key = "unif",
     adjustment = "cos",
     order = c(1, 2))

Ajuste Hermite pollynomial usa od código "herm" e polinomial simples "poly".

Podemos incluir covariáveis utilizando o argumento formula = ~ .... Abaixo, está especificado um modelo “Hazard-rate” para os dados de cutia q ue inclui o tempo de senso como covariável e uma distância limite de 20m.

cutia_hr_time <- cutia_tap_arap_15 |> 
  ds(truncation = 20,
     key = "hr",
     formula = ~ cense_time)

Adicionando uma segunda covariável: tamanho do grupo.

cutia_hr_time_size <- ds(data = cutia_tap_arap_15,
                     truncation = 20,
                     transect = "line",
                     key = "hr",
                     formula = ~ cense_time + size)
plot(cutia_hr_time)
plot(cutia_hr_time_size)

Checagem e seleção de modelos

Podemos usar a função summary para obter informações importantes sobre o modelo.

summary(cutia_hn)

O resultado inclui detalhes sobre o dado e a especificação do modelo, assim como dos coeficientes (\(\beta_{j}\)) e sua inceteza, a média do valor de detectabilidade e sua incerteza e uma estimativa da abundância na área coberta pela amostragem (sem levar em consideração o tamanho dos agrupamentos, ou bandos).

Bondade de ajuste

Para visualizar quão bem a função de detecção se ajusta aos dados quanto temos as distâncias exatas podemos usar um plot de quantis empíricos x teóricos (Q-Q plot). Ele compara a função de distribuição cumulativa (CDF) dos valores ajustados da função detecção a distribuição empírica dos dados (EDF).

Também podemos usar o teste de Cramér-von Mises para testar se os pontos da EDF e da CDF tem origem na mesma distribuição. O teste usa a soma de todas as distâncias entre um ponto e a linha y = x para formar a estatística a ser testada. Um resultado significativo fornece evidência contra a hiipótese nula, sugerindo que o modelo não se ajusta bem aos dados.

# ajustando um modelo Half-normal
cutia_hn <- ds(data = cutia_tap_arap_15,
                 truncation = 20,
                 transect = "line",
                 key = "hn", 
                 adjustment = NULL)

# conduzindo o teste dfe bondadede ajuste de Cramer-von Mises
gof_ds(cutia_hn)

gof_ds(cutia_hr_time)

O resutlado do teste aponta que o modelo Half-normal deve ser descartado.

Testes de bondade de ajuste de chi-quadrado são gerados usando a função gof_ds quando as distâncias forneceidas estão categorizadas.

Seleção de Modelos

Uma vez que temos um conjunto de modelos plausíveis, podemos utilizar o cirtériode informaçãode Akaike (AIC) para selecionar entre os modelos o que melhor se ajusta aos dados utilizando a função summarize_ds_models.

# gerando uma tabela de seleção de modelos usando AIC
summarize_ds_models(cutia_hn, cutia_hr_time, cutia_hr_time_size)

O melhor modelo é o Hazard-rate com tempo de senso e tamanho do grupo como covariáveis.

Estimando a abundância e a variância

Estimando abundância e variância no R

Para obter a abundância na região de estudo, primeiro calculamos a abundância na área amostrada para obter \(N_c\) e em seguida escalonamos esse valor para toda a área de estudo multiplicando \(N_c\) pela razão entre a área amostrada e a área da região. Para estimar a abundância na área amostrada, utilizamos as estimativas de probabilidade de detecção no estimador de Horvitz-Thompson.

Quando fornecemos os dados no formato correto (“flatfile”) ds irá automaticamente calcular as estimativas de abundância baseado nas informações de amostragem presenta nos dados.

summary(cutia_hn)
  1. Summary statistics: fornece as áreas, aŕea de amostragem, esforço, número de observações, número de transectos, taxa de encontro, seus erros padrões e coeficientes de variação para cada estrato;

  2. Abundance: fornece estimativas, erros padrões, coeficientesde variação, intervalos de confiança inferior e superior, graus de liberdade para a estimativa de abundância de cada estrato;

  3. Densidade: lista as mesmas estatísticas de Abundance, só que para densidade.

Funções Exploratórias Adicionais

contar_n_repeticoes_trilha() - conta o número de vezes que cada trilha foi visitada

LS0tCnRpdGxlOiAiRGlzdGFuY2Ugbm8gUiBjb20gZGFkb3MgJ21vZGVsbyciCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClJldGlyYWRvIGRvIGFydGlnbyBNaWxsZXIgZXQgYWwuICgyMDE5KS4gRGlzdGFuY2Ugc2FtcGxpbmcgaW4gUi4gSm91cm5hbCBvZiBTdGF0aXN0aWNhbCBTb2Z3YXJlIDg5KDEpCgpgYGB7ciBzZXR1cH0KIyBpbnN0YWxhciBwYWNvdGVzIG5lY2Vzc8OhcmlvcwojaW5zdGFsbC5wYWNrYWdlcygiRGlzdGFuY2UiKQoKIyBpbnN0YWxhciBwYWNvdGVzIGFkaWNpb25haXMKI2luc3RhbGwucGFja2FnZXMoIm1yZHMiKQojaW5zdGFsbC5wYWNrYWdlcygiZHNtIikKI2luc3RhbGwucGFja2FnZXMoIm1hZHMiKQojaW5zdGFsbC5wYWNrYWdlcygiZHNpbXMiKQoKIyBjYXJyZWdhciBwYWNvdGVzIApsaWJyYXJ5KERpc3RhbmNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KGZsZXh0YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQoKIyBjYXJyZWdhciBhcyBmdW7Dp8O1ZXMgZGEgcGFzdGEgUgojIGNhcnJlZ2FyIGZ1bsOnw6NvIHNjcmlwdF9jYXJyZWdhcl9mdW7Dp8O1ZXNfcGFzdGFfci5SCnNvdXJjZSgKICBwYXN0ZTAoCiAgICBoZXJlOjpoZXJlKCksCiAgICAiL1IvbWluaGFzX2Z1bmNvZXMuUiIKICApCikKCiMgY2FycmVnYXIgZGFkb3MKY3V0aWFfdGFwX2FyYXAgPC0gdHJhbnNmb3JtYXJfcGFyYV9kaXN0YW5jZVJfY292YXJpYXZlaXMoKSB8PiAKICBmaWx0ZXIoCiAgICB1Y19uYW1lID09ICJSZXNleCBUYXBham9zLUFyYXBpdW5zIiwKICAgIHNwX25hbWUgPT0gIkRhc3lwcm9jdGEgY3JvY29ub3RhIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKICAKIyByZWFkcjo6d3JpdGVfZXhjZWxfY3N2KAojICAgY3V0aWFfdGFwX2FyYXAsCiMgICBwYXN0ZTAoCiMgICAgIGhlcmU6OmhlcmUoKSwKIyAgICAgIi9kYXRhL2N1dGlhX3RhcF9hcmFwLmNzdiIKIyAgICksIAojICkKCmN1dGlhX3RhcF9hcmFwIHw+IAogIERUOjpkYXRhdGFibGUoZmlsdGVyID0gInRvcCIpCmBgYAoKYGBge3J9CmN1dGlhX3RhcF9hcmFwIHw+IAogIGNvdW50KFJlZ2lvbi5MYWJlbCkKCmN1dGlhX3RhcF9hcmFwIHw+IAogIGNvdW50KFNhbXBsZS5MYWJlbCkKYGBgCgojIEZvcm1hdGHDp8OjbyBkbyBjb25qdW50byBkZSBkYWRvcwoKVmFyacOhdmVpcyBuZWNlc3PDoXJpYXMgcGFyYSBvIGBkYXRhLmZyYW1lYDoKCi0gYFJlZ2lvbi5MYWJlbGA6IHZldG9yIGZhdG9yIGNvbSBvIGVzdHJhdG8gY29udGVuZG8gbyB0cmFuc2VjdG8gKHBvZGUgc2VyIHVtYSBlc3RyYXRpZmljYcOnw6NvIHByw6ktYW1vc3RyYWdlbSAtIFVDcyAtIG91IHDDs3MtYW1vc3RyYWdlbSAtIGV4LiByZWdpw6NvLCBlc3RhZG8sIGJpb21hKQoKLSBgQXJlYWA6IHZldG9yIG51bcOpcmljbyBjb250ZW5kbyBhIMOhcmVhIGRvIGVzdHJhdG87CgotIGBTYW1wbGUuTGFiZWxgOiB2ZXRvciBuw7ptZXJpY28gY29udGVuZG8gYSBpZGVudGlkYWRlIChJRCkgZG8gdHJhbnNlY3RvCgotIGBvYmplY3RgOiBub21lIGFkaWNpb25hbCwgdmVyIHNlw6fDo28gNjsKCi0gYGRldGVjdGVkYDogbm9tZSBhZGljaW9uYWwsIHZlciBzZcOnw6NvIDY7CgotIGBFZmZvcnRgOiB2ZXRvciBuw7ptZXJpY28gY29udGVuZG8gbyBlc2ZvcsOnbyBkbyB0cmFuc2VjdG8gKHBhcmEgbGluaGFzIHNldSBjb21wcmltZW50bywgcGFyYSBwb250b3MgbyBuw7ptZXJvIGRlIHZlemVzIHF1ZSBvIHBvbnRvIGZvaSB2aXNpdGFkbykKCi0gYHNpemVgOiB2ZXRvciBudW3DqXJpY28gY29wbnRlbmRvIG8gdGFtYW5obyBkbyBncnVwbyBvYnNlcnZhZG87CgotIGBkaXN0YW5jZWA6IHZldG9yIG51bcOpcmljbyBkZSBkaXN0w6JuY2lhcyBvYnNlcnZhZGFzOwoKLSBgTW9udGhgOgoKLSBgT0JzYDoKCi0gYFNwYDoKCiAtIGBtYXNgOgogCiAtIGBIQVNgOgogCiAtIGBTdHVkeS5BcmVhYDoKIApUcmFuc2VjdG9zIHF1ZSBmb3JhbSBhbW9zdHJhZG9zLCBtYXMgcXVlIG7Do28gdGl2ZXJhbSBvYnNlcnZhw6fDtWVzIChuID0gMCkgZGV2ZW0gc2VyIGluY2x1w61kb3Mgbm8gY29uanVudG8gZGUgZGFkb3MgY29tIGBOQWAgbmFzIG9ic2VydmHDp8O1ZXMgZGUgZGlzdMOibmNpYSBlIHF1YWxxdWVyIG91dHJhIGNvdmFyaWFlbCBwYXJhIGEgcXVhbCBuw6NvIHNlIHRlbmhhIG9ic2VydmHDp8Ojby4KIApgYGB7cn0KIyBjdXRpYV90YXBfYXJhcCB8PiAKIyAgIGNvbXBsZXRlKFJlZ2lvbi5MYWJlbCwgU2FtcGxlLkxhYmVsLCBzcF9uYW1lKSB8PiAKIyAgIGRhdGF0YWJsZShmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpKQpgYGAKCkpvZ2FyIGEgaW1wdXRhY2FvIGRlIGBOQWBzIHByYSBkZW50cm8gZGEgZnVuY2FvIGNhcnJlZ2FyIGRhZG9zIGNvbXBsZXRvcy4KCiMjIERldGVybWluYW5kbyBhIGRpc3TDom5jaWEgcGFyYSB0cnVuY2FyIG9zIGRhZG9zCgpgYGB7ciwgZmlnLmhlaWdodD0xNSwgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQojIGRlc2VuaGEgbyBncmFmaWNvIGNvbSBhIGRpc3RyaWJ1aWNhbyBkZSBkaXN0YW5jaWFzIHBlcnBlbmRpY3VsYXJlcwpjdXRpYV90YXBfYXJhcCB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKCkKYGBgCgogCiMjIEFqdXN0YW5kbyBmdW7Dp8O1ZXMgZGUgZGV0ZWPDp8OjbyBubyBSCgojIyMgQ3V0aWFzIGRhIFJlc2V4IFRhcGFqw7NzLUFyYXBpdW5zCgojIyMjICpIYWxmLU5vcm1hbCogc2VtIHRlcm1vcyBkZSBhanVzdGUKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGFzIGN1dGlhcyAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqSGFsZi1ub3JtYWwqIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgLCBzZW0gdGVybW8gZGUgYWp1c3RlLgoKYGBge3J9CiMgYWp1c3RhbmRvIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBwYXJhIHVtYSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gZGUgMjAgbWV0cm9zCiMgS2V5IGZ1bmN0aW9uIC0gSGFsZi1ub3JtYWwgCmN1dGlhX3RhcF9hcmFwX2huIDwtIGN1dGlhX3RhcF9hcmFwIHw+IAogIGRzKAogICAgdHJ1bmNhdGlvbiA9IDIwLAogICAga2V5ID0gImhuIiwKICAgIGFkanVzdG1lbnQgPSBOVUxMCiAgKQpgYGAKCiMjIyMgKkhhbGYtTm9ybWFsKiBjb20gdGVybW9zIGRlIGFqdXN0ZSAqSGVybWl0ZS1Qb2x5bm9taWFsKgoKQWp1c3RhbmRvIHVtIG1vZGVsbyBhbyBkYWRvcyBkYXMgY3V0aWFzICpEYXN5cHJvY3RhIGNyb2Nvbm90YSosIGNvbmZpZ3VyYW5kbyB1bWEgZGlzdMOibmNpYSBsaW1pdGUgZGUgMjBtIGUgdXNhbmRvICpIYWxmLW5vcm1hbCogY29tbyAqa2V5IGZ1bmN0aW9uKiB1c2FuZG8gbyBhcmd1bWVudG8gYGtleWAsIGNvbSB0ZXJtbyBkZSBhanVzdGUgZG8gdGlwbyAqSGVybWl0ZS1wb2x5bm9taWFsKi4KCmBgYHtyfQojIGFqdXN0YW5kbyBhIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gcGFyYSB1bWEgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIGRlIDIwIG1ldHJvcwojIEtleSBmdW5jdGlvbiAtIEhhbGYtbm9ybWFsIApjdXRpYV90YXBfYXJhcF9obl9oZXJtIDwtIGN1dGlhX3RhcF9hcmFwIHw+IAogIGRzKAogICAgdHJ1bmNhdGlvbiA9IDIwLAogICAga2V5ID0gImhuIiwKICAgIGFkanVzdG1lbnQgPSAiaGVybSIKICApCmBgYAoKIyMjIyAqSGFsZi1Ob3JtYWwqIGNvbSB0ZXJtb3MgZGUgYWp1c3RlICpDb3NpbmUqCgpBanVzdGFuZG8gdW0gbW9kZWxvIGFvIGRhZG9zIGRhcyBjdXRpYXMgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhbGYtbm9ybWFsKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YCwgY29tIHRlcm1vIGRlIGFqdXN0ZSBkbyB0aXBvICpDb3NpbmUqLgoKYGBge3J9CiMgYWp1c3RhbmRvIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBwYXJhIHVtYSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gZGUgMjAgbWV0cm9zCiMgS2V5IGZ1bmN0aW9uIC0gSGFsZi1ub3JtYWwgCmN1dGlhX3RhcF9hcmFwX2huX2NvcyA8LSBjdXRpYV90YXBfYXJhcCB8PiAKICBkcygKICAgIHRydW5jYXRpb24gPSAyMCwKICAgIGtleSA9ICJobiIKICAgICkKYGBgCgojIyMjICpIYXphcmQtUmF0ZSogc2VtIHRlcm1vcyBkZSBhanVzdGUKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGEgY3V0aWEgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhemFyZCByYXRlKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YC4KCmBgYHtyfQojIEtleSBmdW5jdGlvbiAtIEhhemFyZC1yYXRlIApjdXRpYV90YXBfYXJhcF9ociA8LSBjdXRpYV90YXBfYXJhcCB8PiAKICBkcygKICAgIHRydW5jYXRpb24gPSAyMCwKICAgICBrZXkgPSAiaHIiLAogICAgYWRqdXN0bWVudCA9IE5VTEwKICApCmBgYAoKIyMjIyAqSGF6YXJkLVJhdGUqIGNvbSB0ZXJtb3MgZGUgYWp1c3RlICpTaW1wbGUtcG9seW5vbWlhbCoKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGEgY3V0aWEgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhemFyZCByYXRlKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YCBlIHRlcm1vIGRlIGFqdXN0ZSBkbyB0aXBvIHBvbGlub21pYWwgc2ltcGxlcy4KCmBgYHtyfQojIEtleSBmdW5jdGlvbiAtIEhhemFyZC1yYXRlIApjdXRpYV90YXBfYXJhcF9ocl9wb2x5IDwtIGN1dGlhX3RhcF9hcmFwIHw+IAogIGRzKAogICAgdHJ1bmNhdGlvbiA9IDIwLAogICAgIGtleSA9ICJociIsCiAgICBhZGp1c3RtZW50ID0gInBvbHkiCiAgKQpgYGAKCiMjIyMgKkhhemFyZC1SYXRlKiBjb20gdGVybW9zIGRlIGFqdXN0ZSAqQ29zaW5lKgoKQWp1c3RhbmRvIHVtIG1vZGVsbyBhbyBkYWRvcyBkYSBjdXRpYSAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqSGF6YXJkIHJhdGUqIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgIGUgdGVybW8gZGUgYWp1c3RlIGRvIHRpcG8gY29zc2Vuby4KCmBgYHtyfQojIEtleSBmdW5jdGlvbiAtIEhhemFyZC1yYXRlIApjdXRpYV90YXBfYXJhcF9ocl9jb3MgPC0gY3V0aWFfdGFwX2FyYXAgfD4gCiAgZHMoCiAgICB0cnVuY2F0aW9uID0gMjAsCiAgICBrZXkgPSAiaHIiCiAgICApCmBgYAoKCmBgYHtyfQpwbG90KGN1dGlhX3RhcF9hcmFwX2huLCBicmVha3MgPSBzZXEoMCwgMjAsIDIuNSkpCnBsb3QoY3V0aWFfdGFwX2FyYXBfaG5faGVybSwgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2huX2NvcywgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2hyLCBicmVha3MgPSBzZXEoMCwgMjAsIDIuNSkpCnBsb3QoY3V0aWFfdGFwX2FyYXBfaHJfcG9seSwgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2hyX2NvcywgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpgYGAKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGFzIGN1dGlhcywgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKlVuaWZvcm0qIGNvbW8gKmtleSBmdW5jdGlvbiogYSBzw6lyaWEgZGUgYWp1c3RlIGNvbSBvIGFyZ3VtZW50byBgYWRqdXN0bWVudGAgZWUgZXNwZWNpZmljYW5kbyBhIG9yZGVtIGNvbSBvIGFyZ3VtZW50byBgb3JkZXJgLgoKYGBge3J9CmN1dGlhX3VuaWZjb3MgPC0gY3V0aWFfdGFwX2FyYXAgfD4gCiAgZHModHJ1bmNhdGlvbiA9IDIwLAogICAgIGtleSA9ICJ1bmlmIiwKICAgICBhZGp1c3RtZW50ID0gImNvcyIsCiAgICAgb3JkZXIgPSBjKDEsIDIpKQpgYGAKCkFqdXN0ZSAqSGVybWl0ZSBwb2xseW5vbWlhbCogdXNhIG9kIGPDs2RpZ28gYCJoZXJtImAgZSBwb2xpbm9taWFsIHNpbXBsZXMgYCJwb2x5ImAuCgpQb2RlbW9zIGluY2x1aXIgY292YXJpw6F2ZWlzIHV0aWxpemFuZG8gbyBhcmd1bWVudG8gYGZvcm11bGEgPSB+IC4uLmAuIEFiYWl4bywgZXN0w6EgZXNwZWNpZmljYWRvIHVtIG1vZGVsbyAiSGF6YXJkLXJhdGUiIHBhcmEgb3MgZGFkb3MgZGUgY3V0aWEgcSB1ZSBpbmNsdWkgbyB0ZW1wbyBkZSBzZW5zbyBjb21vIGNvdmFyacOhdmVsIGUgdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbS4KCmBgYHtyfQpjdXRpYV9ocl90aW1lIDwtIGN1dGlhX3RhcF9hcmFwXzE1IHw+IAogIGRzKHRydW5jYXRpb24gPSAyMCwKICAgICBrZXkgPSAiaHIiLAogICAgIGZvcm11bGEgPSB+IGNlbnNlX3RpbWUpCmBgYAoKQWRpY2lvbmFuZG8gdW1hIHNlZ3VuZGEgY292YXJpw6F2ZWw6IHRhbWFuaG8gZG8gZ3J1cG8uCgpgYGB7cn0KY3V0aWFfaHJfdGltZV9zaXplIDwtIGRzKGRhdGEgPSBjdXRpYV90YXBfYXJhcF8xNSwKICAgICAgICAgICAgICAgICAgICAgdHJ1bmNhdGlvbiA9IDIwLAogICAgICAgICAgICAgICAgICAgICB0cmFuc2VjdCA9ICJsaW5lIiwKICAgICAgICAgICAgICAgICAgICAga2V5ID0gImhyIiwKICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYSA9IH4gY2Vuc2VfdGltZSArIHNpemUpCmBgYAoKYGBge3J9CnBsb3QoY3V0aWFfaHJfdGltZSkKcGxvdChjdXRpYV9ocl90aW1lX3NpemUpCmBgYAoKIyMgQ2hlY2FnZW0gZSBzZWxlw6fDo28gZGUgbW9kZWxvcwoKUG9kZW1vcyB1c2FyIGEgZnVuw6fDo28gYHN1bW1hcnlgIHBhcmEgb2J0ZXIgaW5mb3JtYcOnw7VlcyBpbXBvcnRhbnRlcyBzb2JyZSBvIG1vZGVsby4KCmBgYHtyfQpzdW1tYXJ5KGN1dGlhX2huKQpgYGAKCk8gcmVzdWx0YWRvICBpbmNsdWkgZGV0YWxoZXMgc29icmUgbyBkYWRvIGUgYSBlc3BlY2lmaWNhw6fDo28gZG8gbW9kZWxvLCBhc3NpbSBjb21vIGRvcyBjb2VmaWNpZW50ZXMgKCRcYmV0YV97an0kKSBlIHN1YSBpbmNldGV6YSwgYSBtw6lkaWEgZG8gdmFsb3IgZGUgZGV0ZWN0YWJpbGlkYWRlIGUgc3VhIGluY2VydGV6YSBlIHVtYSBlc3RpbWF0aXZhIGRhIGFidW5kw6JuY2lhIG5hIMOhcmVhIGNvYmVydGEgcGVsYSBhbW9zdHJhZ2VtIChzZW0gbGV2YXIgZW0gY29uc2lkZXJhw6fDo28gbyB0YW1hbmhvIGRvcyBhZ3J1cGFtZW50b3MsIG91IGJhbmRvcykuIAoKIyMjIEJvbmRhZGUgZGUgYWp1c3RlCgpQYXJhIHZpc3VhbGl6YXIgcXXDo28gYmVtIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBzZSBhanVzdGEgYW9zIGRhZG9zIHF1YW50byB0ZW1vcyBhcyBkaXN0w6JuY2lhcyBleGF0YXMgcG9kZW1vcyB1c2FyIHVtIHBsb3QgZGUgcXVhbnRpcyBlbXDDrXJpY29zIHggdGXDs3JpY29zIChRLVEgcGxvdCkuIEVsZSBjb21wYXJhIGEgZnVuw6fDo28gZGUgZGlzdHJpYnVpw6fDo28gY3VtdWxhdGl2YSAoQ0RGKSBkb3MgdmFsb3JlcyBhanVzdGFkb3MgZGEgZnVuw6fDo28gZGV0ZWPDp8OjbyBhIGRpc3RyaWJ1acOnw6NvIGVtcMOtcmljYSBkb3MgZGFkb3MgKEVERikuIAoKVGFtYsOpbSBwb2RlbW9zIHVzYXIgbyB0ZXN0ZSBkZSBDcmFtw6lyLXZvbiBNaXNlcyBwYXJhIHRlc3RhciBzZSBvcyBwb250b3MgZGEgRURGIGUgZGEgQ0RGIHRlbSBvcmlnZW0gbmEgbWVzbWEgZGlzdHJpYnVpw6fDo28uIE8gdGVzdGUgdXNhIGEgc29tYSBkZSB0b2RhcyBhcyBkaXN0w6JuY2lhcyBlbnRyZSB1bSBwb250byBlIGEgbGluaGEgeSA9IHggcGFyYSBmb3JtYXIgYSBlc3RhdMOtc3RpY2EgYSBzZXIgdGVzdGFkYS4gVW0gcmVzdWx0YWRvIHNpZ25pZmljYXRpdm8gZm9ybmVjZSBldmlkw6puY2lhIGNvbnRyYSBhIGhpaXDDs3Rlc2UgbnVsYSwgc3VnZXJpbmRvIHF1ZSBvIG1vZGVsbyBuw6NvIHNlIGFqdXN0YSBiZW0gYW9zIGRhZG9zLgoKYGBge3J9CiMgYWp1c3RhbmRvIHVtIG1vZGVsbyBIYWxmLW5vcm1hbApjdXRpYV9obiA8LSBkcyhkYXRhID0gY3V0aWFfdGFwX2FyYXBfMTUsCiAgICAgICAgICAgICAgICAgdHJ1bmNhdGlvbiA9IDIwLAogICAgICAgICAgICAgICAgIHRyYW5zZWN0ID0gImxpbmUiLAogICAgICAgICAgICAgICAgIGtleSA9ICJobiIsIAogICAgICAgICAgICAgICAgIGFkanVzdG1lbnQgPSBOVUxMKQoKIyBjb25kdXppbmRvIG8gdGVzdGUgZGZlIGJvbmRhZGVkZSBhanVzdGUgZGUgQ3JhbWVyLXZvbiBNaXNlcwpnb2ZfZHMoY3V0aWFfaG4pCgpnb2ZfZHMoY3V0aWFfaHJfdGltZSkKYGBgCgpPIHJlc3V0bGFkbyBkbyB0ZXN0ZSBhcG9udGEgcXVlIG8gbW9kZWxvICpIYWxmLW5vcm1hbCogZGV2ZSBzZXIgZGVzY2FydGFkby4KClRlc3RlcyBkZSBib25kYWRlIGRlIGFqdXN0ZSBkZSBjaGktcXVhZHJhZG8gc8OjbyBnZXJhZG9zIHVzYW5kbyBhIGZ1bsOnw6NvIGBnb2ZfZHNgIHF1YW5kbyBhcyBkaXN0w6JuY2lhcyBmb3JuZWNlaWRhcyBlc3TDo28gY2F0ZWdvcml6YWRhcy4KCiMjIyBTZWxlw6fDo28gZGUgTW9kZWxvcwoKVW1hIHZleiBxdWUgdGVtb3MgdW0gY29uanVudG8gZGUgbW9kZWxvcyBwbGF1c8OtdmVpcywgcG9kZW1vcyB1dGlsaXphciBvIGNpcnTDqXJpb2RlIGluZm9ybWHDp8Ojb2RlIEFrYWlrZSAoQUlDKSBwYXJhIHNlbGVjaW9uYXIgZW50cmUgb3MgbW9kZWxvcyBvIHF1ZSBtZWxob3Igc2UgYWp1c3RhIGFvcyBkYWRvcyB1dGlsaXphbmRvIGEgZnVuw6fDo28gYHN1bW1hcml6ZV9kc19tb2RlbHNgLgoKYGBge3J9CiMgZ2VyYW5kbyB1bWEgdGFiZWxhIGRlIHNlbGXDp8OjbyBkZSBtb2RlbG9zIHVzYW5kbyBBSUMKc3VtbWFyaXplX2RzX21vZGVscyhjdXRpYV9obiwgY3V0aWFfaHJfdGltZSwgY3V0aWFfaHJfdGltZV9zaXplKQpgYGAKCk8gbWVsaG9yIG1vZGVsbyDDqSBvIEhhemFyZC1yYXRlIGNvbSB0ZW1wbyBkZSBzZW5zbyBlIHRhbWFuaG8gZG8gZ3J1cG8gY29tbyBjb3ZhcmnDoXZlaXMuCgojIyBFc3RpbWFuZG8gYSBhYnVuZMOibmNpYSBlIGEgdmFyacOibmNpYQoKIyMjIEVzdGltYW5kbyBhYnVuZMOibmNpYSBlIHZhcmnDom5jaWEgbm8gUgoKUGFyYSBvYnRlciBhIGFidW5kw6JuY2lhIG5hIHJlZ2nDo28gZGUgZXN0dWRvLCBwcmltZWlybyBjYWxjdWxhbW9zIGEgYWJ1bmTDom5jaWEgbmEgw6FyZWEgYW1vc3RyYWRhIHBhcmEgb2J0ZXIgJE5fYyQgZSBlbSBzZWd1aWRhIGVzY2Fsb25hbW9zIGVzc2UgdmFsb3IgcGFyYSB0b2RhIGEgw6FyZWEgZGUgZXN0dWRvIG11bHRpcGxpY2FuZG8gJE5fYyQgcGVsYSByYXrDo28gZW50cmUgYSDDoXJlYSBhbW9zdHJhZGEgZSBhIMOhcmVhIGRhIHJlZ2nDo28uIFBhcmEgZXN0aW1hciBhIGFidW5kw6JuY2lhIG5hIMOhcmVhIGFtb3N0cmFkYSwgdXRpbGl6YW1vcyBhcyBlc3RpbWF0aXZhcyBkZSBwcm9iYWJpbGlkYWRlIGRlIGRldGVjw6fDo28gbm8gZXN0aW1hZG9yIGRlIEhvcnZpdHotVGhvbXBzb24uCgpRdWFuZG8gZm9ybmVjZW1vcyBvcyBkYWRvcyBubyBmb3JtYXRvIGNvcnJldG8gKCJmbGF0ZmlsZSIpIGBkc2AgaXLDoSBhdXRvbWF0aWNhbWVudGUgY2FsY3VsYXIgYXMgZXN0aW1hdGl2YXMgZGUgYWJ1bmTDom5jaWEgYmFzZWFkbyBuYXMgaW5mb3JtYcOnw7VlcyBkZSBhbW9zdHJhZ2VtIHByZXNlbnRhIG5vcyBkYWRvcy4KCmBgYHtyfQpzdW1tYXJ5KGN1dGlhX2huKQpgYGAKCjEuIFN1bW1hcnkgc3RhdGlzdGljczogZm9ybmVjZSBhcyDDoXJlYXMsIGHFlWVhIGRlIGFtb3N0cmFnZW0sIGVzZm9yw6dvLCBuw7ptZXJvIGRlIG9ic2VydmHDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcywgdGF4YSBkZSBlbmNvbnRybywgc2V1cyBlcnJvcyBwYWRyw7VlcyBlIGNvZWZpY2llbnRlcyBkZSB2YXJpYcOnw6NvIHBhcmEgY2FkYSBlc3RyYXRvOwoKMi4gQWJ1bmRhbmNlOiBmb3JuZWNlIGVzdGltYXRpdmFzLCBlcnJvcyBwYWRyw7VlcywgY29lZmljaWVudGVzZGUgdmFyaWHDp8OjbywgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IsIGdyYXVzIGRlIGxpYmVyZGFkZSBwYXJhIGEgZXN0aW1hdGl2YSBkZSBhYnVuZMOibmNpYSBkZSBjYWRhIGVzdHJhdG87CgozLiBEZW5zaWRhZGU6IGxpc3RhIGFzIG1lc21hcyBlc3RhdMOtc3RpY2FzIGRlIEFidW5kYW5jZSwgc8OzIHF1ZSBwYXJhIGRlbnNpZGFkZS4KCiMjICoqRnVuw6fDtWVzIEV4cGxvcmF0w7NyaWFzIEFkaWNpb25haXMqKgoKYGNvbnRhcl9uX3JlcGV0aWNvZXNfdHJpbGhhKClgIC0gY29udGEgbyBuw7ptZXJvIGRlIHZlemVzIHF1ZSBjYWRhIHRyaWxoYSBmb2kgdmlzaXRhZGE=